package com.haiyou.common.thread.task;

import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;

import com.github.rholder.retry.Retryer;
import com.github.rholder.retry.RetryerBuilder;
import com.github.rholder.retry.StopStrategies;
import com.github.rholder.retry.WaitStrategies;
import com.haiyou.common.constants.ErrCode;
import com.haiyou.common.spring.schedule.RunnableScheduledTask;
import com.haiyou.common.util.check.Assert;

import lombok.Getter;
import lombok.extern.slf4j.Slf4j;

/**
 * 
 * @Description: 重试次数的任务
 * @author xingyuan
 * @date 2022年11月25日 上午10:26:27
 */
@Slf4j
public abstract class AbstractRetryTask<Ser> extends AbstractRunnableCoreTask{


	/**
	 * 重试次数
	 */
	@Getter
	private int retry = 0;
	
	/**
	 * 已运行次数
	 */
	@Getter
	private int runNum;
	
	@Getter
	private final Ser _ser;
	
	/**
	 * 重试间隔
	 */
	@Getter
	private long delay;
	
	/**
	 * 时间单位
	 */
	@Getter
	private TimeUnit timeUnit;

	/**
	 * 重试器
	 */
	private Retryer<Boolean> retryer;
	
	/**
	 * 默认实现
	 * @param ser
	 */
	@SuppressWarnings("null")
	public AbstractRetryTask(Ser ser) {
		super();
		this._ser = ser;
		this.retry = 5;
		this.delay = 30;
		this.timeUnit = TimeUnit.SECONDS;
		
		this.retryer = RetryerBuilder.<Boolean>newBuilder()
				//重试异常
				.retryIfExceptionOfType(Exception.class)
				//重试次数
				.withStopStrategy(StopStrategies.stopAfterAttempt(retry))
				//固定间隔
				.withWaitStrategy(WaitStrategies.fixedWait(delay, timeUnit))
				.build();
	}
	
	@SuppressWarnings("null")
	public AbstractRetryTask(Ser ser,int retry,long delay,TimeUnit timeUnit) {
		super();
		this._ser = ser;
		this.retry = retry;
		this.delay = delay;
		this.timeUnit = timeUnit;
		
		Assert.isTrue(retry > 0, ErrCode.ERROR_PARAMETER,"init retry task must > 0");
		Assert.isTrue(timeUnit != null, ErrCode.ERROR_PARAMETER,"init retry task timeUnit not null");

		this.retryer = RetryerBuilder.<Boolean>newBuilder()
				//重试异常
				.retryIfExceptionOfType(Exception.class)
				//重试次数
				.withStopStrategy(StopStrategies.stopAfterAttempt(retry))
				//固定间隔
				.withWaitStrategy(WaitStrategies.fixedWait(delay, timeUnit))
				
				.build();
	}
	
	/**
	 * 直接间隔重试
	 * @param ser
	 * @param retry
	 */
	@SuppressWarnings("null")
	public AbstractRetryTask(Ser ser,int retry) {
		super();
		this._ser = ser;
		this.retry = retry;
		
		Assert.isTrue(retry > 0, ErrCode.ERROR_PARAMETER,"init retry task must > 0");
		this.retryer = RetryerBuilder.<Boolean>newBuilder()
				//重试异常
				.retryIfExceptionOfType(Exception.class)
				//重试次数
				.withStopStrategy(StopStrategies.stopAfterAttempt(retry))
				.build();
	}
	
	
	/**
	 * 直接设置重试器
	 * @param ser
	 * @param retryer
	 */
	public AbstractRetryTask(Ser ser,Retryer<Boolean> retryer) {
		super();
		this._ser = ser;
		Assert.isTrue(retryer != null, ErrCode.ERROR_PARAMETER,"init retry task retryer not null");
		this.retryer = retryer;
	}
	
	
	@Override
	final protected void exec() throws Exception {
		
		retryer.call(new Callable<Boolean>() {
			@Override
			public Boolean call() throws Exception {
				//运行次数+1
				runNum++;
				retryExec();
				return true;
			}
		});
		
	}
	
	/**
	 * 重试执行业务
	 * @throws Exception
	 */
	protected abstract void retryExec() throws Exception;
	
}
